<template>
  <div class="navClass">
    <el-menu mode="vertical" class="menu" @select="onSelect" v-if="list.length" :default-active="activeIndex">
      <el-menu-item :key="index" :index="index" v-for="(item, index) in list">
        {{ item.innerText }}
      </el-menu-item>
    </el-menu>
  </div>
</template>
<script lang="ts" setup>
import { debounce } from 'lodash'
import { defineProps, reactive, toRefs, onMounted, onBeforeUnmount, withDefaults } from 'vue'
interface Props {
  wrapperClass: any
  boxClass: any
  titleClass: string
}
interface State {
  box: any
  nav: any
  list: any[]
  activeIndex: number
  navTop: number
}
const props = withDefaults(defineProps<Props>(), {})
const state: State = reactive({
  list: [],
  activeIndex: 0,
  box: null,
  nav: null,
  navTop: 0
})

onMounted(() => {
  state.box = document.querySelector(`.${props.boxClass}`) as any[0]
  state.list = state.box.getElementsByClassName(props.titleClass)
  state.nav = document.getElementsByClassName('navClass')[0]
  state.navTop = state.nav.offsetTop
  window.addEventListener('scroll', onScroll, true)
})
onBeforeUnmount(() => {
  window.removeEventListener('scroll', onScroll, true)
})
const isInViePortOfOne = (el: HTMLElement) => {
  const viewPortHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
  const viewPortWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth
  const { top, right, bottom, left } = el.getBoundingClientRect()
  return top >= 0 && left >= 0 && bottom <= viewPortHeight && right <= viewPortWidth
}

const onScroll = debounce(() => {
  const wrapper = document.querySelector(`.${props.wrapperClass}`) as any[0]
  const activeIndex = [...state.list].findIndex((i: any) => isInViePortOfOne(i))
  state.activeIndex = activeIndex
  if (wrapper.scrollTop >= state.navTop - 140) {
    state.nav.style.left = state.nav.offsetLeft + 'px'
    state.nav.style.top = '140px'
    state.nav.style.position = 'fixed'
  } else {
    state.nav.style.position = ''
  }
})
const onSelect = (index: number) => {
  // eslint-disable-next-line vue/no-mutating-props
  const wrapper = document.querySelector(`.${props.wrapperClass}`) as any[0]
  wrapper.scrollTop = state.list[index].offsetTop
}
const { list, activeIndex } = toRefs(state)
</script>
<style scoped lang="stylus">
.navClass
  width: 15%
.menu
  border-left: solid 1px var(--el-menu-border-color);
  border-right: unset;
  margin-left: 30px;
  :deep(.is-active::before)
    content: '';
    height: 20px;
    width: 2px;
    background: var(--el-color-primary-dark);
    position: relative;
    right: 21px;
</style>
